package com.sinodata.bsm.center.bean;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.quartz.CronExpression;

import com.sinodata.bsm.center.cache.NotifyDelayRuleCache;
import com.sinodata.bsm.center.cache.NotifyEventTypeRuleCache;
import com.sinodata.bsm.center.cache.NotifyExcludeResRuleCache;
import com.sinodata.bsm.center.cache.NotifyPauseRuleCache;
import com.sinodata.bsm.center.cache.NotifyReceiveRuleCache;
import com.sinodata.bsm.center.cache.NotifyRuleCache;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.NotifyConstants;
import com.sinodata.bsm.common.vo.NotifyDelayRule;
import com.sinodata.bsm.common.vo.NotifyEventTypeRule;
import com.sinodata.bsm.common.vo.NotifyExcludeResRule;
import com.sinodata.bsm.common.vo.NotifyPauseRule;
import com.sinodata.bsm.common.vo.NotifyReceiveRule;
import com.sinodata.bsm.common.vo.NotifyRule;

/**
 * <p>
 * Description: 通知规则Bean对象
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-29 PM 5:15:40     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
public class NotifyRuleBean {

    /**
     * logger
     */
    private static final Logger logger = Logger.getLogger(NotifyRuleBean.class);

    /**
     * 通知规则缓存
     */
    private static NotifyRuleCache notifyRuleCache = SpringContextHolder.getBean(NotifyRuleCache.class);

    /**
     * 通知接收规则缓存
     */
    private static NotifyReceiveRuleCache notifyReceiveRuleCache = SpringContextHolder.getBean(NotifyReceiveRuleCache.class);

    /**
     * 通知暂停规则缓存
     */
    private static NotifyPauseRuleCache notifyPauseRuleCache = SpringContextHolder.getBean(NotifyPauseRuleCache.class);

    /**
     * 通知排除规则缓存
     */
    private static NotifyExcludeResRuleCache notifyExcludeResRuleCache = SpringContextHolder.getBean(NotifyExcludeResRuleCache.class);

    /**
     * 通知事件类别规则缓存
     */
    private static NotifyEventTypeRuleCache notifyEventTypeRuleCache = SpringContextHolder.getBean(NotifyEventTypeRuleCache.class);

    /**
     * 通知延迟规则缓存
     */
    private static NotifyDelayRuleCache notifyDelayRuleCache = SpringContextHolder.getBean(NotifyDelayRuleCache.class);

    /**
     * 通知规则
     */
    private final NotifyRule notifyRule;

    /**
     * 通知接收规则
     */
    private final List<NotifyReceiveRule> notifyReceiveRules;

    /**
     * 通知暂停规则
     */
    private final List<NotifyPauseRule> notifyPauseRules;

    /**
     * 通知排除子资源规则
     */
    private final List<NotifyExcludeResRule> notifyExcludeResRules;

    /**
     * 通知适应的事件类别规则
     */
    private final List<NotifyEventTypeRule> notifyEventTypeRules;

    /**
     * 通知延迟规则
     */
    private final List<NotifyDelayRule> notifyDelayRules;

    /**
     * 构建方法
     * 
     * @param notifyRule
     * @param receiveRule
     * @param pauseRule
     * @param excludeResRule
     * @param eventTypeRule
     * @param notifyDelayRule
     */
    public NotifyRuleBean(NotifyRule notifyRule, List<NotifyReceiveRule> receiveRule, List<NotifyPauseRule> pauseRule, List<NotifyExcludeResRule> excludeResRule, List<NotifyEventTypeRule> eventTypeRule, List<NotifyDelayRule> notifyDelayRule) {
        this.notifyRule = notifyRule;
        this.notifyReceiveRules = receiveRule;
        this.notifyPauseRules = pauseRule;
        this.notifyExcludeResRules = excludeResRule;
        this.notifyEventTypeRules = eventTypeRule;
        this.notifyDelayRules = notifyDelayRule;
    }

    /**
     * 获取通知规则Bean对象，数据从缓存中获取
     * 
     * @param id
     * @return
     */
    public static NotifyRuleBean get(Long id) {
        NotifyRule notifyRule = notifyRuleCache.get(id);
        Long notifyRuleId = notifyRule.getId();
        List<NotifyReceiveRule> receiveRule = notifyReceiveRuleCache.getByNotifyRule(notifyRuleId);
        List<NotifyPauseRule> pauseRule = notifyPauseRuleCache.getByNotifyRule(notifyRuleId);
        List<NotifyExcludeResRule> excludeResRule = notifyExcludeResRuleCache.getByNotifyRule(notifyRuleId);
        List<NotifyEventTypeRule> eventTypeRule = notifyEventTypeRuleCache.getByNotifyRule(notifyRuleId);
        List<NotifyDelayRule> notifyDelayRule = notifyDelayRuleCache.getByNotifyRule(notifyRuleId);
        return new NotifyRuleBean(notifyRule, receiveRule, pauseRule, excludeResRule, eventTypeRule, notifyDelayRule);
    }

    /**
     * 根据延迟规则获取下次一个合适的通知时间，即: 如果时间落在延迟规则范围内，则到延迟规则结束时间
     * 
     * @param time
     * @return
     */
    public long getNextValidNotifyTime(long time) {
        Calendar cal = Calendar.getInstance();
        int dayTime = cal.get(Calendar.MINUTE);
        dayTime += cal.get(Calendar.HOUR_OF_DAY) * 60;
        if (this.notifyDelayRules != null) {
            for (int i = 0; i < this.notifyDelayRules.size(); i++) {
                long delayTime = 0L;
                NotifyDelayRule r = this.notifyDelayRules.get(i);
                int start = r.getStartTime() / 60;
                int end = r.getEndTime() / 60;
                if (start < 0 || end < 0 || start == end) {
                    continue;
                }
                if (start > end) {
                    if (dayTime >= start) {
                        delayTime = System.currentTimeMillis() + (1440 - dayTime + end) * 60000L;
                    } else if (dayTime <= end) {
                        delayTime = System.currentTimeMillis() + (end - dayTime) * 60000L;
                    }
                } else {
                    if (dayTime >= start && dayTime <= end) {
                        delayTime = System.currentTimeMillis() + (end - dayTime) * 60000L;
                    }
                }
                if (delayTime > time) {
                    time = delayTime;
                }
            }
        }
        return time;
    }

    /**
     * 获取通知规则
     * 
     * @return
     */
    public NotifyRule notifyRule() {
        return notifyRule;
    }

    /**
     * 获取通知接收规则
     * 
     * @return
     */
    public List<NotifyReceiveRule> getNotifyReceiveRules() {
        return notifyReceiveRules;
    }

    /**
     * 获取通知暂停规则
     * 
     * @return
     */
    public List<NotifyPauseRule> getNotifyPauseRules() {
        return notifyPauseRules;
    }

    /**
     * 获取通知排除子资源规则
     * 
     * @return
     */
    public List<NotifyExcludeResRule> getNotifyExcludeResRules() {
        return notifyExcludeResRules;
    }

    /**
     * 获取通知适用的事件类别规则
     * 
     * @return
     */
    public List<NotifyEventTypeRule> getNotifyEventTypeRules() {
        return notifyEventTypeRules;
    }

    /**
     * 获取通知延迟规则
     * 
     * @return
     */
    public List<NotifyDelayRule> getNotifyDelayRules() {
        return notifyDelayRules;
    }

    /**
     * 根据资源、事件类别、事件级别获取有效的通知规则
     * 先获取资源全部的通知规则，按级别过滤，再按是否禁用过滤，再看该资源是否排除，再按事件类别过滤
     * 
     * @param resId
     * @param eventTypeId
     * @param level
     * @return
     */
    public static List<NotifyRuleBean> getAvailableNotifyRules(Long resId, Long eventTypeId, Integer level) {
        List<NotifyRuleBean> list = new ArrayList<NotifyRuleBean>();
        List<NotifyRule> rules = notifyRuleCache.getAllByRes(resId);
        //按级别来放入到 list 中
        for (NotifyRule notifyRule : rules) {
            String levels = notifyRule.getEventLevels();
            if (levels != null) {
                String[] levelArray = levels.split("[,]");
                for (int j = 0; j < levelArray.length; j++) {
                    if (levelArray[j].equals(String.valueOf(level))) {
                        list.add(NotifyRuleBean.get(notifyRule.getId()));
                        break;
                    }
                }
            }
        }
        //按是否禁用、排除资源、事件类别来，不符合的排除
        for (int m = list.size() - 1; m >= 0; m--) {
            NotifyRuleBean notifyRuleBean = list.get(m);
            //禁用的排除
            if (NotifyConstants.RULE_STATUS_DISABLE == notifyRuleBean.notifyRule.getStatus()) {
                list.remove(m);
                continue;
            }
            //排除排除资源的规则
            List<NotifyExcludeResRule> notifyExcludeResRules = notifyRuleBean.getNotifyExcludeResRules();
            if (notifyExcludeResRules != null && notifyExcludeResRules.size() != 0) {
                for (NotifyExcludeResRule notifyExcludeResRule : notifyExcludeResRules) {
                    if (resId.equals(notifyExcludeResRule.getResId())) {
                        list.remove(m);
                        continue;
                    }
                }
            }
            //处于暂停的规则排除
            List<NotifyPauseRule> notifyPauseRules = notifyRuleBean.getNotifyPauseRules();
            if (notifyPauseRules != null && notifyPauseRules.size() != 0) {
                if (isPause(notifyPauseRules)) {
                    list.remove(m);
                    continue;
                }
            }
            //按事件类别移除
            List<NotifyEventTypeRule> notifyEventTypeRules = notifyRuleBean.getNotifyEventTypeRules();
            if (notifyEventTypeRules != null && notifyEventTypeRules.size() != 0) {
                boolean remove = true;
                for (NotifyEventTypeRule notifyEventTypeRule : notifyEventTypeRules) {
                    if (notifyEventTypeRule.getEventTypeId().equals(eventTypeId)) {
                        remove = false;
                    }
                }
                if (remove) {
                    list.remove(m);
                }
            }
        }
        return list;
    }

    /**
     * 判断是否暂停
     * 
     * @param pauseRules
     * @return
     */
    private static boolean isPause(List<NotifyPauseRule> pauseRules) {
        if (pauseRules == null || pauseRules.size() == 0) {
            return false;
        }
        for (NotifyPauseRule notifyPauseRule : pauseRules) {
            String startTime = notifyPauseRule.getStartTime();
            int duration = notifyPauseRule.getDuration();
            try {
                CronExpression cron = new CronExpression(startTime);
                Date d = new Date(System.currentTimeMillis() - duration * 1000L);
                d = cron.getNextValidTimeAfter(d);
                if (d.getTime() <= System.currentTimeMillis()) {
                    return true;
                } else {
                    continue;
                }
            } catch (ParseException e) {
                logger.error("incorrect format of notify rule", e);
            }
        }
        return false;
    }

}